import { Page } from '@/models';
import { arrayFormater, FormatOption } from '@/utils';
import { isEmpty } from '@/utils/is';
import { Result } from '@/utils/request/type';
import useLoadMore from '@/utils/request/useLoadMore';
import { Empty, Select, SelectProps, Spin } from 'antd';
import { FC, useCallback, useState } from 'react';

export type RequestFn<T extends Record<string, unknown>> = (
  params: T & {
    pageSize: number;
    pageNum: number;
  }
) => Result<Page<T>>;
export interface BaseSelectProps extends SelectProps<any> {
  request: RequestFn<any>;
  params?: Record<string, any>;
  beforeOptions?: Record<string, any>[];
  defaultSelectedOptions?: Record<string, any>[];
  searchFieldName?: string;
  debounceInterval?: number;
  fieldNames?: FormatOption;
}
const BaseSelect: FC<BaseSelectProps> = (props) => {
  const {
    request,
    params,
    searchFieldName = 'name',
    defaultSelectedOptions = [],
    fieldNames,
    debounceInterval = 300,
    beforeOptions = [],
    onChange,
    ...anyProps
  } = props;
  const activeFieldNames = { label: 'label', value: 'value', disabled: 'disabled', ...fieldNames };
  const [search, setSearch] = useState<string | undefined>();
  const req = useLoadMore(request, {
    defaultParams: [
      {
        ...params,
        [searchFieldName]: search
      }
    ],
    manual: anyProps.disabled,
    refreshDeps: [params, search, searchFieldName],
    debounceInterval,
    isNoMore: (d) => (d ? d.list.length >= d.rowCount : false)
  });
  const handleSearch = useCallback((value: string) => {
    setSearch(value);
  }, []);
  const hasValues = req.data?.list.find((i: any) => i[activeFieldNames.value] === anyProps.value);
  const showOptions = [...beforeOptions, ...(req.data?.list || [])];
  if (!hasValues && anyProps.value) {
    showOptions.push(
      {
        [activeFieldNames.value]: null,
        [typeof activeFieldNames.label === 'function' ? 'label' : activeFieldNames.label]: '...',
        [activeFieldNames.disabled]: true
      },
      ...defaultSelectedOptions.filter((i) => !isEmpty(i[activeFieldNames.value]))
    );
  }
  return (
    <Select
      placeholder='请选择'
      onChange={(v) => {
        onChange &&
          onChange(
            v,
            showOptions.find((i) => i[activeFieldNames.value] === v)
          );
      }}
      {...anyProps}
      loading={req.loading}
      showSearch
      searchValue={search}
      allowClear={true}
      filterOption={false}
      notFoundContent={
        <Spin spinning={req.loading}>
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
        </Spin>
      }
      onSearch={handleSearch}
      onPopupScroll={(e) => {
        const { target } = e;
        const { scrollTop, offsetHeight, scrollHeight } = target as HTMLDivElement;
        if (scrollHeight - (scrollTop + offsetHeight) < 10 && !req.loadingMore) {
          req.loadMore();
        }
      }}
      options={arrayFormater(showOptions, activeFieldNames) as any}
    />
  );
};

export default BaseSelect;
